package com.fulihui.information.core.redis;

import com.fulihui.information.core.db.ContentCounterDB;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.Collections.emptyList;
import static org.near.toolkit.common.StringUtil.isNotBlank;
import static org.springframework.util.CollectionUtils.isEmpty;

/**
 * @author Willard.Hu on 2016/12/28 0028.
 */
@Component("redisContentCounterDB")
public class RedisContentCounterDB implements ContentCounterDB {
    private final transient Logger log = LoggerFactory.getLogger(getClass());

    // 数据字典, key: 统计类型; value: redis key
    private static final Map<CounterType, String> DICT = Maps.newHashMap();

    static {
        // 内容阅读次数记录，允许每个用户多次操作
        DICT.put(CounterType.READ_TIMES, "INFORMATION:CONTENT_READTIMES_COUNTER_DB");
        // 内容被赞次数记录，一个用户操作只做一次统计
        DICT.put(CounterType.UPVOTE, "INFORMATION:CONTENT_UPVOTE_COUNTER_DB");
        // 内容被踩次数记录，一个用户操作只做一次统计
        DICT.put(CounterType.DOWNVOTE, "INFORMATION:CONTENT_DOWNVOTE_COUNTER_DB");
        // 内容被分享次数记录，允许每个用户多次操作
        DICT.put(CounterType.SHARED_TIMES, "INFORMATION:CONTENT_SHARED_COUNTER_DB");
        // 内容被评论次数记录，允许每个用户多次操作
        DICT.put(CounterType.COMMENT_TIMES, "INFORMATION:CONTENT_COMMENT_COUNTER_DB");
        // 内容被收藏次数记录，由上层业务层控制同一个内容不能被用户重复收藏，但取消收藏后，还可以再次收藏并计数，满足条件，在调用自增方法
        DICT.put(CounterType.STAR_TIMES, "INFORMATION:CONTENT_STAR_COUNTER_DB");
    }

    @Autowired
    private JedisPool jedisPool;

    public void setJedisPool(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }

    /**
     * @see ContentCounterDB#incr(ContentCounterDB.CounterType, String)
     */
    @Override
    public long incr(ContentCounterDB.CounterType key, String contentId) {
        // 默认自增1
        return incrBy(key, contentId, 1);
    }

    /**
     * @see ContentCounterDB#incrBy(CounterType, String, int)
     */
    @Override
    public long incrBy(CounterType key, String contentId, int num) {
        Assert.notNull(key);
        Assert.hasLength(contentId);
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hincrBy(DICT.get(key), contentId, num);
        }
    }

    /**
     * @see ContentCounterDB#singleTimes(ContentCounterDB.CounterType, String)
     */
    @Override
    public long singleTimes(ContentCounterDB.CounterType key, String contentId) {
        Assert.notNull(key);
        Assert.hasLength(contentId);
        try (Jedis jedis = jedisPool.getResource()) {
            String value = jedis.hget(DICT.get(key), contentId);
            return isNotBlank(value) ? Long.parseLong(value) : 0;
        }
    }

    /**
     * @see ContentCounterDB#multiTimes(ContentCounterDB.CounterType, List)
     */
    @Override
    public List<Long> multiTimes(ContentCounterDB.CounterType key, List<String> contentIds) {
        Assert.notNull(key);
        if (isEmpty(contentIds)) {
            return emptyList();
        }
        try (Jedis jedis = jedisPool.getResource()) {
            String[] fields = contentIds.toArray(new String[contentIds.size()]);
            return jedis.hmget(DICT.get(key), fields).stream()
                    .map(it -> it != null ? Long.parseLong(it) : 0L)
                    .collect(Collectors.toList());
        }
    }

    /**
     * @see ContentCounterDB#multiDelete(CounterType, String...)
     */
    @Override
    public boolean multiDelete(CounterType key, String... contentId) {
        Assert.notNull(key);
        if (contentId == null || contentId.length == 0) {
            return false;
        }
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hdel(DICT.get(key), contentId) > 0;
        }
    }

    /**
     * @see ContentCounterDB#getAll(CounterType)
     */
    @Override
    public Map<String, String> getAll(CounterType key) {
        Assert.notNull(key);
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hgetAll(DICT.get(key));
        }
    }
}
